home *** CD-ROM | disk | FTP | other *** search
- unit PCX;
-
- (* This is a unit to read .PCX files and put them in displayable form. The
- actual work of decoding the file and moving the data into memory is done
- in assembler and is quite fast. (You don't need TASM or any knowledge of
- assembly language. As long as PCXOBJ.OBJ is present, it will be linked
- into the unit when you compile.)
-
- The following display modes are supported:
-
- Mode TP Graphmode Resolution Colors
- ~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~
- $04 CGAC0 to C3 320 x 200 4
- $06 CGAHi 640 x 200 2
- $0E EGALo/VGALo 640 x 200 16
- $10 EGAHi/VGAMed 640 x 350 16
- $12 VGAHi 640 x 480 16
-
- Some tinkering would no doubt make the unit usable with the 320 x
- 200 x 16-color modes. The 320 x 200 x 256-color mode is dealt with in a
- companion unit, PCX256.PAS.
-
- It's assumed that the image is the width of the screen and that you will
- set the correct display mode. The unit doesn't check to see what format
- the .PCX image is in, and you have to pass in the appropriate driver
- as a parameter.
-
- For the CGA formats, the unit is set up to put the data into two buffers
- on the heap, from where it can be moved into the two display memory
- banks. See CGASHOW for an example. You can of course alter the unit
- to move the data directly into display memory.
-
- For EGA and VGA formats, the data is written to page 0 of the video
- buffer. This can easily be changed by setting "page_addr" to a different
- value. Three different techniques of hiding the image while it is being
- written are demonstrated in SHOWEGA, SHOWVGA, and SHOW256.
-
- References:
- ~~~~~~~~~~
- Richard F. Ferraro, "Programmer's Guide to the EGA and VGA Cards"
- (Addison-Wesley, 1988).
-
- Richard Wilton, "Programmer's Guide to PC and PS/2 Video Systems"
- (Microsoft, 1987).
-
- "Technical Reference Manual [for Paintbrush]" (Zsoft, 1988). The
- information in this slim booklet is also found in a file distributed
- with at least some versions of Microsoft/PC Paintbrush.
-
- Software:
- ~~~~~~~~
- Besides the various incarnations of Paintbrush (ZSoft and Microsoft),
- the excellent Deluxe Paint II Enhanced (Electronic Arts) can also create
- files in .PCX format. Other graphics programs have conversion utilities.
- *)
-
- (* --------------------------------------------------------------------- *)
-
- INTERFACE
-
- uses DOS, GRAPH;
-
- type RGBrec = record
- redval, greenval, blueval: integer;
- end;
-
- var pcxfilename: pathstr;
- file_error: boolean;
- pal: palettetype;
- RGBpal: array[0..15] of RGBrec;
- page_addr: word;
- buff1, buff2: pointer;
-
- { CGA display memory banks: }
- screenbuff1: array[0..7999] of byte absolute $b800:$0000;
- screenbuff2: array[0..7999] of byte absolute $b800:$2000;
-
- const page0 = $A000; { EGA/VGA display segment }
- EGApage1 = $A800;
-
- procedure READ_PCX_FILE(pdriver: integer; pfilename: pathstr);
-
- (* ------------------------------------------------------------------ *)
-
- IMPLEMENTATION
-
- var datalength: word;
- scratch: pointer;
- buff1seg, buff2seg: word;
- plane: word;
- is_CGA: boolean;
- is_VGA: boolean;
- evenrow: boolean;
- repeatcount: byte;
- columncount, linestart: word;
-
- type ptrRec = record
- ofs, seg: word;
- end;
-
- const buffsize = 65521; { Largest possible }
-
- procedure DECODE_PCX; external;
- {$L pcxobj}
-
- procedure READ_PCX_FILE(pdriver: integer; pfilename: pathstr);
-
- var entry, gun, pcxcode, mask, colorID: byte;
- palbuf: array[0..47] of byte;
- pcxfile: file;
-
- begin { READ_PCX_FILE }
- is_CGA:= (pdriver = CGA); { 2 or 4 colors }
- is_VGA:= (pdriver = VGA); { 16 of 256K possible colors }
- { Otherwise EGA - 16 of 64 possible colors }
- assign(pcxfile, pfilename);
- {$I-} reset(pcxfile, 1); {$I+}
- file_error:= (IOresult <> 0);
- if file_error then exit;
-
- (* To minimize disk access and speed things up, we read the file into a
- scratchpad on the heap. Large files have to be done in two or more
- chunks because of the 64K limit on dynamic memory variables. *)
-
- getmem(scratch, buffsize); { Allocate scratchpad }
- blockread(pcxfile, scratch^, 128); { Get header into scratchpad }
-
- (* The .PCX file has a 128-byte header. Most of it can be ignored if you're
- working with a known format. All we want is the palette information. *)
-
- inc(ptrRec(scratch).ofs, 16); { Scrap first 16 bytes }
- move(scratch^, palbuf, 48); { Get palette info }
-
- (* ------------------------ Setup for CGA ----------------------------- *)
-
- if is_CGA then
- begin { Allocate memory for CGA map }
- getmem(buff1, 8000);
- getmem(buff2, 8000);
- buff1seg:= ptrRec(buff1).seg; { Segment of buffers, for assembler }
- buff2seg:= ptrRec(buff2).seg;
- evenrow:= false;
- end else
-
- (* ---------------------- Setup for EGA/VGA ---------------------------- *)
-
- begin
- port[$3C4]:= 2; { Index to map mask register }
- plane:= 1; { Initialize plane }
- port[$3C5]:= plane; { Set sequencer to mask out other planes }
-
- (* -------------------- Decipher EGA/VGA palette ----------------------- *)
-
- (* The palette information is stored in bytes 16-63 of the header. Each of
- the 16 palette slots is allotted 3 bytes - one for each primary color.
- Any of these bytes can have a value of 0-255.
-
- For the EGA there are just 4 significant settings, since only 64
- different colors (4 x 4 x 4) are available. Hence for EGA-format images
- we divide the codes by 64. The absolute color number for the palette
- entry is derived by setting one of bits 0-2 and one of bits 3-5 with the
- mask corresponding to the .PCX code byte. (In binary form, the absolute
- color number may be thought of as 00rgbRGB.) This number is then passed
- into Turbo's SetAllPalette procedure.
-
- For the VGA things work differently. Here we must use Turbo's
- SetRGBPalette procedure to change the red, green, and blue values in the
- 16 active color registers. The registers expect values in the range 0-63
- (64 x 64 x 64 = 256K, the number of possible colors), so we divide the
- .PCX codes by 4. A further complication is that by default the palette
- entries point to the color registers corresponding to the standard EGA
- colors, so we must change them to point to registers 0-15 instead (or
- else modify registers 0-5, 20, 7, and 56-63). See SHOWVGA.PAS for an
- example of how to set the palette and the registers. *)
-
- for entry:= 0 to 15 do
- begin
- colorID:= 0;
- for gun:= 0 to 2 do
- begin
- pcxcode:= palbuf[entry * 3 + gun]; { Get primary color value }
- if not is_VGA then
- begin { Interpret for EGA }
- case (pcxcode div $40) of
- 0: mask:= $00; { 000000 }
- 1: mask:= $20; { 100000 }
- 2: mask:= $04; { 000100 }
- 3: mask:= $24; { 100100 }
- end;
- colorID:= colorID or (mask shr gun); { Define two bits }
- end { not is_VGA }
- else
- begin { is_VGA }
- with RGBpal[entry] do { Interpret for VGA }
- case gun of
- 0: redval:= pcxcode div 4;
- 1: greenval:= pcxcode div 4;
- 2: blueval:= pcxcode div 4;
- end;
- end; { is_VGA }
- end; { gun }
- if is_VGA then pal.colors[entry]:= entry
- else pal.colors[entry]:= colorID;
- end; { entry }
- pal.size:= 16;
- end; { not is_CGA }
-
- (* ----------------- Read and decode the image data ------------------- *)
-
- dec(ptrRec(scratch).ofs, 16); { Reset pointer }
- repeatcount:= 0; { Initialize assembler vars. }
- columncount:= 0;
- linestart:= 0;
- repeat
- blockread(pcxfile, scratch^, buffsize, datalength);
- decode_pcx; { Call assembler routine }
- until eof(pcxfile);
- close(pcxfile);
- if not is_CGA then port[$3C5]:= $F; { Reset mask map }
- freemem(scratch,buffsize); { Discard scratchpad }
- end; { READ_PCX_FILE }
-
- (* -------------------------- Initialization ----------------------------- *)
-
- BEGIN
- page_addr:= page0; { Destination for EGA/VGA data }
- END.
-